﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Controller;
using GACore.ReversiGA;
using NN = NNCore;

namespace Reversi
{
	public partial class FormBoard : Form
	{
		private UserControl userControl;

		private PlayerTypes player1 = PlayerTypes.Player;
		private PlayerTypes player2 = PlayerTypes.Computer;
		private string settingsNeuralNet1;
		private string settingsNeuralNet2;
		private int timerInterval = 1500;

		private ReversiGAMapper reversiGAMapper;
		private FormGASettings formGASettings;

		private GACore.Preferences gaPreferences;
		private string gaPrefFilename = "GAPreferences.xml";

		public FormBoard()
		{
			InitializeComponent();
		}

		#region Events

		private void FormBoard_Load(object sender, EventArgs e)
		{
			openFileDialog1.Filter = "XML (*.xml)|*.xml";
			ChangeUI(new UCStart());
		}

		private void btnNew_Click(object sender, EventArgs e)
		{
			NewGame();
		}

		private void btnRun100_Click(object sender, EventArgs e)
		{
			gamesEnded = 0;
			player1Wins = 0;
			player2Wins = 0;
			List<ReversiController> controllers = new List<ReversiController>();
			for (int i = 0; i < 1000; i++)
			{
				NN.Controller nnController1 = null;
				NN.Controller nnController2 = null;
				if (player1 == PlayerTypes.NN)
				{
					nnController1 = new NN.Controller(settingsNeuralNet1);
				}
				if (player2 == PlayerTypes.NN)
				{
					nnController2 = new NN.Controller(settingsNeuralNet2);
				}

				ReversiController rController = new ReversiController(player1, player2, nnController1, nnController2, 1, 2, false);
				rController.WinnerFound += reversi_WinnerFound;
				rController.GameEnded += reversi_GameEnded;
				rController.TimerInterval = 1;
				rController.StartGame();
				controllers.Add(rController);
			}


		}

		private int gamesEnded = 0;
		private void reversi_GameEnded(object sender, GameEndedEventArgs args)
		{
			gamesEnded++;
			if (gamesEnded == 1000)
			{
				ErrorHandler.ShowInformation(string.Format("Spieler 1 hat {0} von {1} Spielen gewonnen und somit {2}%{3}{4}% der Spiele endeten unentschieden.",
					player1Wins, gamesEnded,
					(player1Wins * 100) / gamesEnded, Environment.NewLine,
					100 * (gamesEnded - (player1Wins + player2Wins)) / gamesEnded), "Beenden");
				gamesEnded = 0;
			}
		}

		private int gamesWithWinner = 0;
		private int player1Wins = 0;
		private int player2Wins = 0;

		private void reversi_WinnerFound(object sender, WinnerFoundEventArgs e)
		{
			gamesWithWinner++;
			if (e.Winner == 1)
				player1Wins++;
			if (e.Winner == 2)
				player2Wins++;
		}


		private void btnShowFields_Click(object sender, EventArgs e)
		{
			if (userControl is UCGame)
			{
				((UCGame)userControl).ShowPossibleMoves();
			}
		}

		private void btnChangeSettings_Click(object sender, EventArgs e)
		{
			ChangeSettings();
		}

		private void changeSettings_SettingsChanged(object sender, SettingsChangedEventArgs e)
		{
			player1 = e.Player1;
			player2 = e.Player2;
			timerInterval = e.TimerInterval;
			settingsNeuralNet1 = e.SettingsNeuralNet1;
			settingsNeuralNet2 = e.SettingsNeuralNet2;
		}

		private void tlStrpMIOptimize_Click(object sender, EventArgs e)
		{
			StartNNOptimization();
		}

		private void tlStrpMISettingsGA_Click(object sender, EventArgs e)
		{
			ChangeGASettings();
		}

		#endregion

		#region Work

		private void ChangeSettings()
		{
			if (userControl is UCGame && ((UCGame)userControl).IsRunning)
			{
				if (MessageBox.Show("Möchten Sie das Spiel wirklich beenden?", "Beenden", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
						== System.Windows.Forms.DialogResult.Yes)
				{
					ChangeUI(new UCStart(player1, player2, settingsNeuralNet1, settingsNeuralNet2, timerInterval));
				}
			}
			else
			{
				ChangeUI(new UCStart(player1, player2, settingsNeuralNet1, settingsNeuralNet2, timerInterval));
			}
		}

		private void NewGame()
		{

			if (userControl is UCGame && ((UCGame)userControl).IsRunning &&
				MessageBox.Show("Möchten Sie das Spiel wirklich neu starten?", "Neustart",
					MessageBoxButtons.YesNo, MessageBoxIcon.Question)
						!= DialogResult.Yes)
			{
				return;
			}
			else
			{
				NN.Controller nnController1 = null;
				NN.Controller nnController2 = null;
				if (player1 == PlayerTypes.NN)
				{
					nnController1 = new NN.Controller(settingsNeuralNet1);
				}
				if (player2 == PlayerTypes.NN)
				{
					nnController2 = new NN.Controller(settingsNeuralNet2);
				}

				ChangeUI(new UCGame(player1, player2, nnController1, nnController2, timerInterval));
			}


		}

		private void ChangeUI(UserControl control)
		{
			control.Dock = DockStyle.Fill;
			spltCMain.Panel1.Controls.Clear();
			spltCMain.Panel1.Controls.Add(control);
			userControl = control;

			if (userControl is UCGame)
			{
			}
			else if (userControl is UCStart)
			{
				((UCStart)userControl).SettingsChanged += new UCStart.SettingsChangedEventHandler(changeSettings_SettingsChanged);
			}
		}

		private void StartNNOptimization()
		{
			try
			{
				if (gaPreferences != null)
				{
					reversiGAMapper = new ReversiGAMapper(gaPreferences);
				}
				else
				{
					if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
					{
						this.gaPrefFilename = openFileDialog1.FileName;
						reversiGAMapper = new ReversiGAMapper(gaPrefFilename);
					}
					else
					{
						return;
					}
				}
				FormOptimization fo = new FormOptimization(reversiGAMapper, gaPreferences);
				fo.ShowDialog();
			}
			catch (Exception e)
			{
				ErrorHandler.ShowError(e.Message, "Fehler während der Optimierung");
			}
		}

		private void ChangeGASettings()
		{
			formGASettings = new FormGASettings(gaPreferences, gaPrefFilename);
			if (formGASettings.ShowDialog() == System.Windows.Forms.DialogResult.OK)
			{
				this.gaPreferences = formGASettings.Preferences;
				this.gaPrefFilename = formGASettings.Filename;
			}
		}

		#endregion

	}
}
